home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1994 April / Inside Multimedia CD-ROM (April 1994).iso / prg / gs / gssource.exe / GSCHAR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  20.1 KB  |  665 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gschar.c */
  21. /* Character writing operators for Ghostscript library */
  22. #include "gx.h"
  23. #include "memory_.h"
  24. #include "string_.h"
  25. #include "gserrors.h"
  26. #include "gxfixed.h"            /* ditto */
  27. #include "gxarith.h"
  28. #include "gxmatrix.h"
  29. #include "gzstate.h"            /* must precede gzdevice */
  30. #include "gzdevice.h"            /* must precede gxchar */
  31. #include "gxdevmem.h"
  32. #include "gxchar.h"
  33. #include "gxcache.h"
  34. #include "gxfont.h"
  35. #include "gspath.h"
  36. #include "gzpath.h"
  37. #include "gzcolor.h"
  38.  
  39. /* Exported size of enumerator */
  40. const uint gs_show_enum_sizeof = sizeof(gs_show_enum);
  41.  
  42. /* Imported procedures */
  43. extern void gx_set_black(P1(gs_state *));
  44.  
  45. /* Forward declarations */
  46. private int continue_kshow(P1(gs_show_enum *));
  47. private int continue_show(P1(gs_show_enum *));
  48. private int continue_show_update(P1(gs_show_enum *));
  49. private int show_setup(P3(gs_show_enum *, gs_state *, const char *));
  50. private int show_ctm_setup(P1(gs_show_enum *));
  51. private int stringwidth_setup(P3(gs_show_enum *, gs_state *, const char *));
  52.  
  53. /* Print the ctm if debugging */
  54. #define print_ctm(s,pgs)\
  55.   dprintf7("[p]%sctm=[%g %g %g %g %g %g]\n", s,\
  56.        pgs->ctm.xx, pgs->ctm.xy, pgs->ctm.yx, pgs->ctm.yy,\
  57.        pgs->ctm.tx, pgs->ctm.ty)
  58.  
  59. /* ------ String writing operators ------ */
  60.  
  61. /* Setup macros for show operators */
  62. #define setup_show()\
  63.   penum->size = strlen(str)
  64. #define setup_show_n()\
  65.   penum->size = size
  66. #define setup_a()\
  67.   penum->add = 1, penum->ax = ax, penum->ay = ay,\
  68.   penum->slow_show = 1
  69. #define setup_width()\
  70.   penum->wchr = chr, penum->wcx = cx, penum->wcy = cy,\
  71.   penum->slow_show = 1
  72. #define no_chr ~(char_code)0
  73.  
  74. /* show[_n] */
  75. int
  76. gs_show_init(register gs_show_enum *penum,
  77.   gs_state *pgs, const char *str)
  78. {    setup_show();
  79.     penum->slow_show = 0;
  80.     return show_setup(penum, pgs, str);
  81. }
  82. int
  83. gs_show_n_init(register gs_show_enum *penum,
  84.   gs_state *pgs, const char *str, uint size)
  85. {    setup_show_n();
  86.     penum->slow_show = 0;
  87.     return show_setup(penum, pgs, str);
  88. }
  89.  
  90. /* ashow[_n] */
  91. int
  92. gs_ashow_init(register gs_show_enum *penum,
  93.   gs_state *pgs, floatp ax, floatp ay, const char *str)
  94. {    int code;
  95.     setup_show();
  96.     code = show_setup(penum, pgs, str);
  97.     setup_a();
  98.     return code;
  99. }
  100. int
  101. gs_ashow_n_init(register gs_show_enum *penum,
  102.   gs_state *pgs, floatp ax, floatp ay, const char *str, uint size)
  103. {    int code;
  104.     setup_show_n();
  105.     code = show_setup(penum, pgs, str);
  106.     setup_a();
  107.     return code;
  108. }
  109.  
  110. /* widthshow[_n] */
  111. int
  112. gs_widthshow_init(register gs_show_enum *penum,
  113.   gs_state *pgs, floatp cx, floatp cy, char chr, const char *str)
  114. {    int code;
  115.     setup_show();
  116.     code = show_setup(penum, pgs, str);
  117.     setup_width();
  118.     return code;
  119. }
  120. int
  121. gs_widthshow_n_init(register gs_show_enum *penum,
  122.   gs_state *pgs, floatp cx, floatp cy, char chr, const char *str, uint size)
  123. {    int code;
  124.     setup_show_n();
  125.     code = show_setup(penum, pgs, str);
  126.     setup_width();
  127.     return code;
  128. }
  129.  
  130. /* awidthshow[_n] */
  131. int
  132. gs_awidthshow_init(register gs_show_enum *penum,
  133.   gs_state *pgs, floatp cx, floatp cy, char chr, floatp ax, floatp ay,
  134.   const char *str)
  135. {    int code;
  136.     setup_show();
  137.     code = show_setup(penum, pgs, str);
  138.     setup_a();
  139.     setup_width();
  140.     return code;
  141. }
  142. int
  143. gs_awidthshow_n_init(register gs_show_enum *penum,
  144.   gs_state *pgs, floatp cx, floatp cy, char chr, floatp ax, floatp ay,
  145.   const char *str, uint size)
  146. {    int code;
  147.     setup_show_n();
  148.     code = show_setup(penum, pgs, str);
  149.     setup_a();
  150.     setup_width();
  151.     return code;
  152. }
  153.  
  154. /* kshow[_n] */
  155. int
  156. gs_kshow_init(register gs_show_enum *penum,
  157.   gs_state *pgs, const char *str)
  158. {    int code;
  159.     if ( pgs->font->FontType == ft_composite)
  160.         return_error(gs_error_invalidfont);
  161.     setup_show();
  162.     code = show_setup(penum, pgs, str);
  163.     penum->do_kern = penum->slow_show = 1;
  164.     return code;
  165. }
  166. int
  167. gs_kshow_n_init(register gs_show_enum *penum,
  168.   gs_state *pgs, const char *str, uint size)
  169. {    int code;
  170.     if ( pgs->font->FontType == ft_composite)
  171.         return_error(gs_error_invalidfont);
  172.     setup_show_n();
  173.     code = show_setup(penum, pgs, str);
  174.     penum->do_kern = penum->slow_show = 1;
  175.     return code;
  176. }
  177.  
  178. /* ------ Related operators ------ */
  179.  
  180. /* stringwidth[_n] */
  181. int
  182. gs_stringwidth_init(gs_show_enum *penum, gs_state *pgs, const char *str)
  183. {    setup_show();
  184.     return stringwidth_setup(penum, pgs, str);
  185. }
  186. int
  187. gs_stringwidth_n_init(gs_show_enum *penum, gs_state *pgs, const char *str, uint size)
  188. {    setup_show_n();
  189.     return stringwidth_setup(penum, pgs, str);
  190. }
  191.  
  192. /* Common code for stringwidth[_n] */
  193. private int
  194. stringwidth_setup(gs_show_enum *penum, gs_state *pgs, const char *str)
  195. {    int code = (penum->slow_show = 0, show_setup(penum, pgs, str));
  196.     if ( code < 0 ) return_error(code);
  197.     penum->stringwidth_flag = 1;
  198.     /* Do an extra gsave and suppress output */
  199.     if ( (code = gs_gsave(pgs)) < 0 ) return code;
  200.     penum->level = pgs->level;    /* for level check in show_update */
  201.     gx_device_no_output(pgs);
  202.     /* Establish an arbitrary current point. */
  203.     return gx_path_add_point(pgs->path, pgs->ctm.tx_fixed, pgs->ctm.ty_fixed);
  204. }
  205.  
  206. /* charpath[_n] */
  207. int
  208. gs_charpath_init(gs_show_enum *penum, gs_state *pgs,
  209.   const char *str, int bool)
  210. {    int code;
  211.     setup_show();
  212.     code = show_setup(penum, pgs, str);
  213.     penum->charpath_flag = (bool ? 2 : 1);
  214.     penum->can_cache = 0;
  215.     return code;
  216. }
  217. int
  218. gs_charpath_n_init(gs_show_enum *penum, gs_state *pgs,
  219.   const char *str, uint size, int bool)
  220. {    int code;
  221.     setup_show_n();
  222.     code = show_setup(penum, pgs, str);
  223.     penum->charpath_flag = (bool ? 2 : 1);
  224.     penum->can_cache = 0;
  225.     return code;
  226. }
  227.  
  228. /* ------ Width/cache operators ------ */
  229.  
  230. /* setcachedevice */
  231. int
  232. gs_setcachedevice(register gs_show_enum *penum, gs_state *pgs,
  233.   floatp wx, floatp wy, floatp llx, floatp lly, floatp urx, floatp ury)
  234. {    int code = gs_setcharwidth(penum, pgs, wx, wy);    /* default is don't cache */
  235.     if ( code < 0 ) return code;
  236.     /* See if we want to cache this character. */
  237.     if ( pgs->in_cachedevice )        /* no recursion! */
  238.         return 0;
  239.     pgs->in_cachedevice = 1;    /* disable color/gray/image operators */
  240.     /* We can only use the cache if ctm is unchanged */
  241.     /* (aside from a possible translation), */
  242.     /* and if the extent of the box is non-negative. */
  243.     if ( !penum->can_cache || !pgs->char_tm_valid ||
  244.          llx > urx || lly > ury
  245.        )
  246.         return 0;
  247.        {    gs_font_dir *dir = pgs->font->dir;
  248.         gs_fixed_point cbox_ll, cbox_ur, cdim;
  249.         long iwidth, iheight;
  250.         cached_char *cc;
  251.         gs_fixed_rect clip_box;
  252.         gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cbox_ll);
  253.         gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cbox_ur);
  254.         cdim.x = cbox_ur.x - cbox_ll.x;
  255.         cdim.y = cbox_ur.y - cbox_ll.y;
  256.         if ( cdim.x < 0 ) cdim.x = -cdim.x;
  257.         if ( cdim.y < 0 ) cdim.y = -cdim.y;
  258. #ifdef DEBUG
  259. if ( gs_debug['k'] )
  260.    {    dprintf4("[k]cbox=[%g %g %g %g]\n",
  261.          fixed2float(cbox_ll.x), fixed2float(cbox_ll.y),
  262.          fixed2float(cbox_ur.x), fixed2float(cbox_ur.y));
  263.     print_ctm("  ", pgs);
  264.    }
  265. #endif
  266.         iwidth = fixed2long(cdim.x) + 2;
  267.         iheight = fixed2long(cdim.y) + 2;
  268.         if (    iwidth != (ushort)iwidth ||
  269.             iheight != (ushort)iheight
  270.            )
  271.           return 0;        /* much too big */
  272.         if ( !penum->dev_cache_set )
  273.            {    /* Set up the memory device for the character cache */
  274.             device *dev = &penum->dev_cache_dev;
  275.             penum->dev_cache_info = mem_mono_device;
  276.             dev->info = (gx_device *)&penum->dev_cache_info;
  277.             dev->is_band_device = 0;
  278.             dev->white = 1;
  279.             dev->black = 1;
  280.             penum->dev_cache_set = 1;
  281.            }
  282.         if ( (cc = gx_alloc_char_bits(dir,
  283.                     (gx_device_memory *)&penum->dev_cache_info,
  284.                     (ushort)iwidth,
  285.                     (ushort)iheight)) == 0 )
  286.           return 0;        /* too big for cache */
  287.         /* The mins handle transposed coordinate systems.... */
  288.         /* Truncate the offsets to avoid artifacts later. */
  289.         cc->offset.x = fixed_ceiling(-min(cbox_ll.x, cbox_ur.x));
  290.         cc->offset.y = fixed_ceiling(-min(cbox_ll.y, cbox_ur.y));
  291. #ifdef DEBUG
  292. if ( gs_debug['k'] )
  293.         dprintf2("[k]offset=[%g %g]\n", fixed2float(cc->offset.x),
  294.              fixed2float(cc->offset.y));
  295. #endif
  296.         if ( !color_is_pure(pgs->dev_color) )    /* can't use cache */
  297.            {    gx_free_cached_char(dir, cc);
  298.             return code;
  299.            }
  300.         if ( (code = gs_gsave(pgs)) < 0 )
  301.            {    gx_free_cached_char(dir, cc);
  302.             return code;
  303.            }
  304.         /* Nothing can go wrong now.... */
  305.         penum->cc = cc;
  306.         cc->code = gs_show_current_char(penum);
  307.         cc->wxy = penum->wxy;
  308.         /* Install the device */
  309.         pgs->device = &penum->dev_cache_dev;
  310.         pgs->device_is_shared = 1;    /* don't deallocate */
  311.         /* Adjust the translation in the graphics context */
  312.         /* so that the character lines up with the cache. */
  313.         gs_translate_to_fixed(pgs, cc->offset.x, cc->offset.y);
  314.         /* Set the initial matrix for the cache device. */
  315.         penum->dev_cache_info.initial_matrix = ctm_only(pgs);
  316.         /* Reset the clipping path to match the metrics. */
  317.         clip_box.p.x = clip_box.p.y = 0;
  318.         clip_box.q.x = int2fixed(iwidth);
  319.         clip_box.q.y = int2fixed(iheight);
  320.         if ( (code = gx_clip_to_rectangle(pgs, &clip_box)) < 0 )
  321.           return code;
  322.         gx_set_black(pgs);    /* Set the color to black. */
  323.        }
  324.     penum->width_status = sws_cache;
  325.     return 0;
  326. }
  327.  
  328. /* setcharwidth */
  329. int
  330. gs_setcharwidth(register gs_show_enum *penum, gs_state *pgs, floatp wx, floatp wy)
  331. {    if ( penum->width_status != sws_none )
  332.         return_error(gs_error_undefined);
  333.     gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy);
  334.     penum->width_status = sws_no_cache;
  335.     return 0;
  336. }
  337.  
  338. /* setmetrics */
  339. int
  340. gs_setmetrics(register gs_show_enum *penum, gs_state *pgs,
  341.   const gs_point *psbxy, const gs_point *pwxy)
  342. {    if ( penum->width_status != sws_none )
  343.         return_error(gs_error_undefined);
  344.     if ( psbxy != 0 )
  345.        {    penum->metrics_sb.x = float2fixed(psbxy->x);
  346.         penum->metrics_sb.y = float2fixed(psbxy->y);
  347.         penum->sb_set = 1;
  348.        }
  349.     if ( pwxy != 0 )
  350.        {    penum->metrics_width.x = float2fixed(pwxy->x);
  351.         penum->metrics_width.y = float2fixed(pwxy->y);
  352.         penum->width_set = 1;
  353.        }
  354.     return 0;
  355. }
  356.  
  357. /* ------ Enumerator ------ */
  358.  
  359. /* Do the next step of a show (or stringwidth) operation */
  360. int
  361. gs_show_next(gs_show_enum *penum)
  362. {    return (*penum->continue_proc)(penum);
  363. }
  364.  
  365. /* Continuation procedures */
  366. #define show_fast_move(wxy, pgs)\
  367.   gx_path_add_rel_point_inline(pgs->path, wxy.x, wxy.y)
  368. private int show_update(P1(gs_show_enum *penum));
  369. private int show_move(P1(gs_show_enum *penum));
  370. private int show_proceed(P1(gs_show_enum *penum));
  371. private int show_finish(P1(gs_show_enum *penum));
  372. private int
  373. continue_show_update(register gs_show_enum *penum)
  374. {    int code = show_update(penum);
  375.     if ( code < 0 ) return code;
  376.     code = show_move(penum);
  377.     if ( code != 0 ) return code;
  378.     return show_proceed(penum);
  379. }
  380. private int
  381. continue_show(register gs_show_enum *penum)
  382. {    return show_proceed(penum);
  383. }
  384. /* For kshow, the CTM may have changed, so we have to reestablish */
  385. /* the cached values in the enumerator. */
  386. private int
  387. continue_kshow(register gs_show_enum *penum)
  388. {    int code = show_ctm_setup(penum);
  389.     if ( code < 0 ) return code;
  390.     return show_proceed(penum);
  391. }
  392.  
  393. /* Update position */
  394. private int
  395. show_update(register gs_show_enum *penum)
  396. {    register gs_state *pgs = penum->pgs;
  397.     /* Update position for last character */
  398.     switch ( penum->width_status )
  399.        {
  400.     case sws_none:
  401.         /* Adobe interpreters assume a character width of 0, */
  402.         /* even though the documentation says this is an error.... */
  403.         penum->wxy.x = penum->wxy.y = 0;
  404.         break;
  405.     case sws_cache:
  406.        {    /* Finish installing the cache entry. */
  407.         cached_char *cc = penum->cc;
  408.         int code;
  409.         /* If the BuildChar procedure did a save and a restore, */
  410.         /* it already undid the gsave in setcachedevice. */
  411.         /* We have to check for this by comparing levels. */
  412.         switch ( pgs->level - penum->level )
  413.            {
  414.         default:
  415.             return_error(gs_error_invalidfont);    /* WRONG */
  416.         case 2:
  417.             code = gs_grestore(pgs);
  418.             if ( code < 0 ) return code;
  419.         case 1:
  420.             ;
  421.            }
  422.         gx_add_cached_char(pgs->font->dir, &penum->dev_cache_info,
  423.                    cc, gx_lookup_fm_pair(pgs));
  424.         if ( !penum->stringwidth_flag && !penum->charpath_flag )
  425.           { /* Copy the bits to the real output device. */
  426.             penum->color_loaded = 0;    /* force gx_color_render */
  427.             code = gs_grestore(pgs);
  428.             if ( code < 0 ) return code;
  429.             return gx_image_cached_char(penum, cc);
  430.           }
  431.        }
  432.     case sws_no_cache: ;
  433.        }
  434.     return gs_grestore(pgs);
  435. }
  436.  
  437. /* Move to next character */
  438. private int
  439. show_move(register gs_show_enum *penum)
  440. {    register gs_state *pgs = penum->pgs;
  441.     if ( penum->add )
  442.         gs_rmoveto(pgs, penum->ax, penum->ay);
  443.     if ( penum->str[penum->index - 1] == penum->wchr )
  444.         gs_rmoveto(pgs, penum->wcx, penum->wcy);
  445.     /* wxy is in device coordinates */
  446.        {    int code = show_fast_move(penum->wxy, pgs);
  447.         if ( code < 0 ) return code;
  448.        }
  449.     /* Check for kerning, but not on the last character. */
  450.     if ( penum->do_kern && penum->index < penum->size )
  451.        {    penum->continue_proc = continue_kshow;
  452.         return gs_show_kern;
  453.        }
  454.     return 0;
  455. }
  456. /* Process next character */
  457. private int
  458. show_proceed(register gs_show_enum *penum)
  459. {    register gs_state *pgs = penum->pgs;
  460.     const byte *str = penum->str;
  461.     uint index;
  462.     cached_fm_pair *pair = 0;
  463.     char_code chr;
  464.     int code;
  465.     penum->color_loaded = 0;
  466. more:    /* Proceed to next character */
  467.     if ( penum->can_cache )
  468.        {    /* Loop with cache */
  469.         if ( pair == 0 )
  470.           pair = gx_lookup_fm_pair(pgs);
  471.         if ( penum->stringwidth_flag )
  472.           while ( (index = penum->index++) != penum->size )
  473.             {    cached_char *cc;
  474.             chr = str[index];
  475.             cc = gx_lookup_cached_char(pgs, pair, chr);
  476.             if ( cc == 0 ) goto no_cache;
  477.             /* Character is in cache. */
  478.             code = show_fast_move(cc->wxy, pgs);
  479.             if ( code ) return code;
  480.             }
  481.         else
  482.           while ( (index = penum->index++) != penum->size )
  483.             {    cached_char *cc;
  484.             chr = str[index];
  485.             cc = gx_lookup_cached_char(pgs, pair, chr);
  486.             if ( cc == 0 ) goto no_cache;
  487.             /* Character is in cache. */
  488.             code = gx_image_cached_char(penum, cc);
  489.             if ( code < 0 ) return code;
  490.             else if ( code > 0 ) goto no_cache;
  491.             if ( penum->slow_show )
  492.                {    penum->wxy = cc->wxy;
  493.                 code = show_move(penum);
  494.                }
  495.             else
  496.                 code = show_fast_move(cc->wxy, pgs);
  497.             if ( code ) return code;
  498.             }
  499.         /* All done. */
  500.         return show_finish(penum);
  501.        }
  502.     else
  503.        {    /* Can't use cache */
  504.         if ( (index = penum->index++) == penum->size )
  505.           {    /* All done. */
  506.             return show_finish(penum);
  507.           }
  508.         chr = str[index];
  509.        }
  510. no_cache:
  511.     /* Character is not cached, client must render it. */
  512.     if ( (code = gs_gsave(pgs)) < 0 ) return code;
  513.     /* Reset the in_cachedevice flag, so that a recursive show */
  514.     /* will use the cache properly. */
  515.     pgs->in_cachedevice = 0;
  516.     /* Set the charpath flag in the graphics context if necessary, */
  517.     /* so that fill and stroke will add to the path */
  518.     /* rather than having their usual effect. */
  519.     pgs->in_charpath = penum->charpath_flag;
  520.     pgs->stroke_adjust = 0;        /* per specification */
  521.        {    gs_fixed_point cpt;
  522.         gx_path *ppath = pgs->path;
  523.         if ( (code = gx_path_current_point_inline(ppath, &cpt)) < 0 )
  524.             return code;
  525.         cpt.x -= pgs->ctm.tx_fixed;
  526.         cpt.y -= pgs->ctm.ty_fixed;
  527.         gs_setmatrix(pgs, &pgs->char_tm);
  528.         cpt.x += pgs->ctm.tx_fixed;
  529.         cpt.y += pgs->ctm.ty_fixed;
  530.         if ( !penum->charpath_flag )
  531.           { /* Round the translation in the graphics state. */
  532.             /* This helps prevent rounding artifacts later. */
  533.             cpt.x = fixed_rounded(cpt.x);
  534.             cpt.y = fixed_rounded(cpt.y);
  535.           }
  536.         gs_translate_to_fixed(pgs, cpt.x, cpt.y);
  537.         gs_newpath(pgs);
  538.         gx_path_add_point(ppath, pgs->ctm.tx_fixed,
  539.                   pgs->ctm.ty_fixed);
  540.        }
  541.     penum->width_status = sws_none;
  542.     penum->width_set = penum->sb_set = 0;
  543.     penum->continue_proc = continue_show_update;
  544.     /* Try using the build procedure in the font. */
  545.     /* < 0 means error, 0 means success, 1 means failure. */
  546.        {    gs_font *pfont = pgs->font;
  547.         code = (*pfont->build_char_proc)(penum, pgs, pfont, chr, pfont->build_char_data);
  548.         if ( code < 0 ) return_error(code);
  549.         if ( code == 0 )
  550.            {    code = show_update(penum);
  551.             if ( code < 0 ) return code;
  552.             penum->color_loaded = 0;
  553.             code = show_move(penum);
  554.             if ( code ) return code;
  555.             goto more;
  556.            }
  557.        }
  558.     return gs_show_render;
  559. }
  560.  
  561. /* Finish show or stringwidth */
  562. private int
  563. show_finish(register gs_show_enum *penum)
  564. {    register gs_state *pgs = penum->pgs;
  565.     int code;
  566.     if ( !penum->stringwidth_flag ) return 0;
  567.     /* Save the accumulated width before returning, */
  568.     /* and undo the extra gsave. */
  569.     code = gs_currentpoint(pgs, &penum->width);
  570.     if ( code < 0 ) return code;
  571.     return gs_grestore(pgs);
  572. }
  573.  
  574. /* Return the current character for rendering. */
  575. char_code
  576. gs_show_current_char(gs_show_enum *penum)
  577. {    return penum->str[penum->index - 1];
  578. }
  579.  
  580. /* Return the just-displayed character for kerning. */
  581. char_code
  582. gs_kshow_previous_char(gs_show_enum *penum)
  583. {    return penum->str[penum->index - 1];
  584. }
  585.  
  586. /* Return the about-to-be-displayed character for kerning. */
  587. char_code
  588. gs_kshow_next_char(gs_show_enum *penum)
  589. {    return penum->str[penum->index];
  590. }
  591.  
  592. /* Return the accumulated width for stringwidth. */
  593. void
  594. gs_show_width(gs_show_enum *penum, gs_point *ppt)
  595. {    *ppt = penum->width;
  596. }
  597.  
  598. /* Return the charpath flag. */
  599. int
  600. gs_show_in_charpath(gs_show_enum *penum)
  601. {    return penum->charpath_flag;
  602. }
  603.  
  604. /* ------ Internal routines ------ */
  605.  
  606. /* Initialize a show enumerator. */
  607. private int
  608. show_setup(register gs_show_enum *penum, gs_state *pgs, const char *str)
  609. {    int code;
  610.     gs_font *pfont = pgs->font;
  611.     penum->pgs = pgs;
  612.     penum->level = pgs->level;
  613.     penum->str = (const byte *)str;    /* avoid signed chars */
  614.     penum->wchr = no_chr;
  615.     penum->add = 0;
  616.     penum->do_kern = 0;
  617.     penum->charpath_flag = 0;
  618.     penum->stringwidth_flag = 0;
  619.     penum->dev_cache_set = 0;
  620.     penum->index = 0;
  621.     penum->continue_proc = continue_show;
  622.     if ( (penum->is_composite = pfont->FontType == ft_composite) )
  623.        {    gs_font *rfont = pgs->font;
  624.         penum->fstack[0] = rfont;
  625.         penum->fdepth = 0;
  626.         penum->pfont =
  627.           rfont->data.type0_data.FDepVector[rfont->data.type0_data.Encoding[0]];
  628.        }
  629.     penum->can_cache = 1;        /* show_ctm_setup may reset */
  630.     code = show_ctm_setup(penum);
  631.     if ( code < 0 ) return code;
  632.     return 0;
  633. }
  634.  
  635. /* Initialize the CTM-related parts of a show enumerator. */
  636. /* We do this both when starting the show operation, */
  637. /* and when returning from the kshow callout. */
  638. private int
  639. show_ctm_setup(gs_show_enum *penum)
  640. {    gs_state *pgs = penum->pgs;
  641.     int code;
  642.     if ( !pgs->char_tm_valid )
  643.        {    /* Compute combined transformation */
  644.         gs_make_identity(&pgs->char_tm);    /* make sure type */
  645.                     /* fields are set in char_tm! */
  646.         code = gs_matrix_multiply(&pgs->font->FontMatrix,
  647.                       &ctm_only(pgs), &pgs->char_tm);
  648.         if ( code < 0 ) return code;
  649.         pgs->char_tm_valid = 1;
  650.        }
  651.     if ( penum->can_cache &= /* no skewing or non-rectangular rotation */
  652.         (is_fzero2(pgs->char_tm.xy, pgs->char_tm.yx) ||
  653.          is_fzero2(pgs->char_tm.xx, pgs->char_tm.yy)) )
  654.        {    gs_fixed_rect cbox;
  655.         gx_cpath_box_for_check(pgs->clip_path, &cbox);
  656.         penum->cxmin = fixed2int_var(cbox.p.x);
  657.         penum->cymin = fixed2int_var(cbox.p.y);
  658.         penum->cxmax = fixed2int_var(cbox.q.x);
  659.         penum->cymax = fixed2int_var(cbox.q.y);
  660.         penum->ftx = (int)fixed2long(float2fixed(pgs->char_tm.tx) - pgs->ctm.tx_fixed);
  661.         penum->fty = (int)fixed2long(float2fixed(pgs->char_tm.ty) - pgs->ctm.ty_fixed);
  662.        }
  663.     return 0;
  664. }
  665.